/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ortus.onlinescrapper;

import ortus.onlinescrapper.themoviedb.ImageItem;
import ortus.onlinescrapper.tools.database;
import java.io.File;
import java.io.FileFilter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ortus.onlinescrapper.themoviedb.Movie;
import ortus.onlinescrapper.themoviedb.TheMovieDB;
import ortus.onlinescrapper.thetvdb.Actor;
import ortus.onlinescrapper.thetvdb.Episode;
import ortus.onlinescrapper.thetvdb.Series;
import ortus.onlinescrapper.thetvdb.TheTVDB;
import sagex.api.Database;
import sagex.api.MediaFileAPI;
import sagex.api.ShowAPI;

/**
 *
 * @author SBANTA
 */
public class api extends ortus.ortusvars {
    public static boolean manual_index_running = false;
    public static boolean index_running = false;
    public static ScanType st = ScanType.None;
    public static boolean cancel_scan = false;
    public static int total_queue = 0;
    public static int total_matches = 0;
    public static int total_match_property = 0;
    public static int total_movies_match = 0;
    public static int total_miss = 0;
    public static int total_series_match = 0;
    public static int total_bypass = 0;
    public static int total_processed = 0;
    public static int current_mediaid;
    public static long scan_start_time = 0;
    public static long scan_end_time = 0;
    static final String TYPE_Recording = "1";
    static final String TYPE_Imported = "2";
    public static final int METADATA_none = 0;
    public static final int METADATA_update = 1;
    public static final int METADATA_full = 2;
    public static final int FANART_none = 0;
    public static final int FANART_update = 1;
    public static final int FANART_full = 2;

private static String getDateTime() {
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date date = new Date();
        return dateFormat.format(date);
    }
 /**
 * Check if indexMedia process is running
 * @return
 */
public static boolean IsindexMediaRunning() {
    return ortus.onlinescrapper.api.index_running;
}
public static void SetIndexMediaRunning(boolean updated_scan_status) {
	ortus.onlinescrapper.api.index_running = updated_scan_status;
}
public static ScanType GetScanType() {
	return st;
}
/**
 * Cancel currently running scan
 */
public static void CancelIndexMedia() {
    ortus.onlinescrapper.api.cancel_scan = true;
}
/**
 * Get the queue size of the current media index scan
 * @return queue size
 */
public static int GetScrapperQueueSize() {
    return ortus.onlinescrapper.api.total_queue;
}
/**
 * Get the number of media items processed by the background scanning process
 * @return
*/
public static Object GetScrapperProcessedRemote() {
    return ortus.daemon.api.executecCMD("192.168.0.15", new Object[] { "ortus.api.GetScrapperProcessed" });
}
public static int GetScrapperProcessed() {
    return ortus.onlinescrapper.api.total_processed;
}

public static HashMap<String,Object> GetScrapperDetail() {
	HashMap<String,Object> sd = new HashMap<String,Object>();
	sd.put("total_queue",total_queue);
        sd.put("total_match_property",total_match_property);
        sd.put("total_matches",total_matches);
        sd.put("total_movies_match",total_movies_match);
        sd.put("total_miss", total_miss);
        sd.put("total_series_match",total_series_match);
        sd.put("total_bypass",total_bypass);
        sd.put("total_processed" , total_processed);
        sd.put("current_mediaid", current_mediaid);
        sd.put("scan_start_time", scan_start_time);
        sd.put("scan_end_time", scan_end_time);
	sd.put("index_running",index_running);
	sd.put("scantype",st);
	return sd;
}
/**
 * Return the percentage completed for a background scan
 * @return Percentage
 */
public static int GetScrapperPercentComplete() {
    float result = (float) (ortus.onlinescrapper.api.total_processed * 1.0 / ortus.onlinescrapper.api.total_queue * 100);
    return Math.round(result);
}
/**
 * Return the percentage of matched media items
 * @return Percentage
 */
public static int GetScrapperPercentMatched() {
    float result = (float) ( GetScrapperMatched() * 1.0 / ( ortus.onlinescrapper.api.total_queue - ortus.onlinescrapper.api.total_bypass) * 100 );
    return Math.round(result);
}
/**
 * Return the percentage of matched media items
 * @return Percentage
 */
public static int GetScrapperPercentMatchedLibrary() {
    List<List> dbresult = ortus.api.executeSQLQueryArray("select count(*) from sage.media where mediatype != 0");
    int matched = 0;
    if ( dbresult.size() == 1) {
 	    matched = Integer.parseInt((String)dbresult.get(0).get(0));
	    float result = (float) ( matched * 1.0 /ortus.onlinescrapper.api.total_queue * 100 );
	    return Math.round(result);
    } else
	    return 0;
}

/**
 * Return the percentage of missed media items
 * @return
 */
public static int GetScrapperPercentMissed() {
    float result = (float) ( GetScrapperMissed() * 1.0 / ( ortus.onlinescrapper.api.total_queue - ortus.onlinescrapper.api.total_bypass) * 100 );
    return Math.round(result);
}
/**
 * Return the percentage of matched media items
 * @return Percentage
 */
public static int GetScrapperPercentMissedLibrary() {
    List<List> dbresult = ortus.api.executeSQLQueryArray("select count(*) from sage.media where mediatype = 0");
    int unmatched = 0;
    if ( dbresult.size() == 1) {
	unmatched = Integer.parseInt((String)dbresult.get(0).get(0));
        float result = (float) ( unmatched * 1.0 /ortus.onlinescrapper.api.total_queue * 100 );
        return Math.round(result);
    } else
	    return 0;
}

/**
 * Get the current media id being processed by the background index scan
 * @return
 */
public static int GetScrapperCurrent() {
    return ortus.onlinescrapper.api.current_mediaid;
}
/**
 * Get the number of matched items in the background index scan
 * @return
 */
public static int GetScrapperMatched() {
    return ortus.onlinescrapper.api.total_movies_match + ortus.onlinescrapper.api.total_series_match;
}
/**
 * Return number of items that matched from a property file
 */
public static int GetScrapperMatchedProperty() {
	return ortus.onlinescrapper.api.total_match_property;
}
/**
 * Return total media items bypassed in background index scan
 * @return
 */
public static int GetScrapperBypassed() {
    return ortus.onlinescrapper.api.total_bypass;
}
/**
 * Get the number of missed items in the background index scan
 * @return
 */
public static int GetScrapperMissed() {
    return ortus.onlinescrapper.api.total_miss;
}
/**
 * Return the start time of background index scan
 * @return
 */
public static long GetScrapperStartTime() {
    return ortus.onlinescrapper.api.scan_start_time;
}
/**
 * Return the end of the last background index scan
 * @return
 */
public static long GetScrapperEndTime() {
    return ortus.onlinescrapper.api.scan_end_time;
}
/**
 * Return the number of minutes the background index scan has been running
 * @return
 */
public static String GetScrapperElapsedMinutes() {

    long millis = new Date().getTime() - ortus.onlinescrapper.api.scan_start_time;

    return String.format("%d min, %d sec",TimeUnit.MILLISECONDS.toMinutes(millis), TimeUnit.MILLISECONDS.toSeconds(millis) -  TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
}
public static List<Object> GetScrapperUnmatchedMedia() {
    return ortus.api.getMediaFilesSQL("select m.mediaid from sage.media as m, sage.scrapperlog as s where m.mediatype = 0 and m.mediaid = s.mediaid group by m.mediaid order by m.mediatitle");
}
public static List<Object> GetScrapperUnmatchedMediaRemote() {
    return ortus.api.executeSQLQuery("select m.mediaid from sage.media as m, sage.scrapperlog as s where m.mediatype = 0 and m.mediaid = s.mediaid group by m.mediaid order by m.mediatitle");
}

public static List<Object> GetScrapperMatchedMedia() {
    return ortus.api.getMediaFilesSQL("select m.mediaid from sage.media as m, sage.scrapperlog as s where m.mediatype != 0 and m.mediaid = s.mediaid group by m.mediaid order by m.mediatitle");
}

public static List<Object> GetScrapperMatches(Object mediafile) {
    return GetScrapperMatches(mediafile,9);
}

public static List<Object> GetScrapperMatches(Object mediafile, int scantype) {
       String sql = "select scrapperid from sage.scrapperlog where mediaid = " + MediaFileAPI.GetMediaFileID(mediafile);
       if ( scantype != 9) {
           sql+=" and scantype = " + scantype;
       }

       return ortus.api.executeSQLQuery(sql);
}
public static int GetScrapperScanType(Object scrapperid) {
       List<Object> result = ortus.api.executeSQLQuery("select scantype from sage.scrapperlog where scrapperid = " + scrapperid);
       if ( result.size() > 0)
            return Integer.parseInt((String)result.get(0));
       else
            return -1;

}
public static String GetScrapperSearchTitle(Object scrapperid) {
       List<Object> result = ortus.api.executeSQLQuery("select searchtitle from sage.scrapperlog where scrapperid = " + scrapperid);
       if ( result.size() > 0)
            return (String)result.get(0);
       else
            return null;
}
public static String GetScrapperFoundTitle(Object scrapperid) {
       List<Object> result = ortus.api.executeSQLQuery("select foundtitle from sage.scrapperlog where scrapperid = " + scrapperid);
       if ( result.size() > 0)
            return (String)result.get(0);
       else
            return null;
}
public static String GetScrapperFoundKey(Object scrapperid) {
       List<Object> result = ortus.api.executeSQLQuery("select foundkey from sage.scrapperlog where scrapperid = " + scrapperid);
       if ( result.size() > 0)
            return (String)result.get(0);
       else
            return null;
}

public static void cleanMedia() {
    HashMap<String,String> validmedia = new HashMap<String,String>();
    int totalclean = 0;
    ortus.api.DebugLog(INFO, "cleanMedia: Starting");
    List<Object> mfl = new ArrayList<Object>(Arrays.asList(MediaFileAPI.GetMediaFiles("VDB")));

    for ( Object o : mfl ) {
        validmedia.put(String.valueOf(MediaFileAPI.GetMediaFileID(o)), "valid");
    }

    List<Object> result = ortus.api.executeSQLQuery("select mediaid, mediatype from sage.media");

    for ( Object o : result) {
        String[] rs = ((String)o).split(",");

        if ( validmedia.get(rs[0]) == null) {
            totalclean++;
            ortus.api.executeSQL("delete from sage.media where mediaid = " + rs[0]);
            if ( rs[1].equals("3")) {
                ortus.api.executeSQL("update sage.episode set mediaid = null where mediaid = " + rs[0]);
            } else {
                ortus.api.executeSQL("delete from sage.mediavideos where mediaid = " + rs[0]);
                ortus.api.executeSQL("delete from sage.cast where mediaid = " + rs[0]);
		ortus.cache.cacheEngine.getInstance().getProvider().Remove(rs[0]);
	    }
        }
    }

    ortus.api.executeSQL("update sage.media set mediatype = 0 where mediatype = 3 and mediaid not in ( select mediaid from sage.episode where mediaid is not null)");
    ortus.api.DebugLog(INFO, "cleanMedia: Completed, removed: " + totalclean);

    return;
}

public static void indexMedia() {
    indexMediaAll(METADATA_update, FANART_update);
}

public static void indexMediaRecordings() {
    st = ScanType.RecordingScan;
    List<Object> mfl = new ArrayList<Object>(Arrays.asList(MediaFileAPI.GetMediaFiles()));
    Database.FilterByBoolMethod(mfl, "IsTVFile", true);

    indexMedia(mfl, METADATA_update, FANART_update);

    cleanMedia();

    st = ScanType.None;
    return;
}

public static void indexMediaAll(int metadata, int fanart) {
    st = ScanType.FullScan;
    List<Object> mfl = new ArrayList<Object>(Arrays.asList(MediaFileAPI.GetMediaFiles("VDB")));
//    Database.FilterByBoolMethod(mfl, "IsTVFile|IsVideoFile|IsDVD|IsBluRay", true);

    indexMedia(mfl, metadata, fanart);

    cleanMedia();

    st = ScanType.None;
    return;
}
public static void indexMedia(List<Object> mfl, int metadata, int fanart) {
        index_running = true;
        cancel_scan = false;
        scan_start_time = new Date().getTime();
        scan_end_time = 0;
        total_queue = mfl.size();
        total_match_property = 0;
        total_movies_match = 0;
        total_miss = 0;
        total_series_match = 0;
        total_bypass = 0;
        total_processed = 0;

        ortus.api.DebugLog(INFO, "indexMedia: Starting");

        HashMap<String,String> mdb = new HashMap<String,String>();

        List<String> bypassregex = ortus.api.DumpLogFile(ortus.api.GetProperty("ortus/basepath","") + java.io.File.separator + "Configuration" + java.io.File.separator + "indexbypass.regex");

        List<Object> dbresult = ortus.api.executeSQLQuery("select mediaid from sage.media where mediatype in (1,2,3,4)");
        if ( dbresult.size() > 0)
            ortus.api.DebugLog(TRACE2," Loading " + dbresult.size() + " existing mediaobjects");
            for ( Object o : dbresult) {
                mdb.put((String)o,(String)o);
            }

        try {
            for ( Iterator<Object> iter = mfl.iterator(); iter.hasNext();) {
		Object obj = iter.next();
                if ( cancel_scan ) {
                    cancel_scan = false;
                    break;
                }
                current_mediaid = MediaFileAPI.GetMediaFileID(obj);
                total_processed++;

                MediaObject mo = new MediaObject(obj, metadata, fanart);

                mo.SetScanType(0);
                
                if ( mdb.get(String.valueOf(MediaFileAPI.GetMediaFileID(obj))) != null)
                   mo.SetMetadataExist();

                if  ( mo.IsMetadataExist() &&
                      ( metadata == METADATA_none || metadata == METADATA_update ) &&
                      ( fanart == FANART_none || fanart == FANART_update )) {
                    total_bypass++;
                    continue;
                }

                if ( MediaFileAPI.GetMediaTitle(obj).isEmpty()) {
                    total_bypass++;
                    continue;
                }

                File mf = MediaFileAPI.GetFileForSegment(obj,0);

                List<Object> result = ortus.api.executeSQLQuery("select mediaid from sage.media where mediaid = " + MediaFileAPI.GetMediaFileID(obj));
                if ( result.size() > 0 )
                    mo.SetMediaExist();
                else
                    ortus.api.DebugLog(TRACE, " media not found for " + MediaFileAPI.GetMediaFileID(obj));

		boolean bypass_media = false;
                for ( String rx : bypassregex ) {
                    Pattern pattern = Pattern.compile(rx);
                    Matcher matcher = pattern.matcher(mf.getAbsolutePath());
                    if ( matcher.matches()) {
			ortus.api.DebugLog(TRACE2,"BypassRegex: found " + mf.getAbsolutePath());
                        if ( ! mo.IsMediaExist() ) {
	                    ortus.api.DebugLog(TRACE2,"BypassRegex: adding file to the db");
                            Movie movie = new Movie();
                            movie.SetMediaGroup(1);
                            movie.SetMediaType(4);
                            movie.WriteDB(mo.GetMedia());
                        }
			bypass_media = true;
                    }
		    if ( bypass_media)
			    break;
                }

		if ( bypass_media) {
		      total_bypass++;
		      continue;
		}

		if ( GetMediaMetaData(mo)) {
			if ( mo.IsMediaTypeSeries())
				total_series_match++;
			else
				total_movies_match++;
		} else {
			total_miss++;
		}
            }
        } catch ( Exception e ) {
            ortus.api.DebugLog(ERROR, "indexMedia: Exception: " + e);
            index_running = false;
            return;
        }

	ortus.api.executeSQL("analyze sample_size 0");
        index_running = false;
        scan_end_time = new Date().getTime();
        ortus.api.DebugLog(INFO, "indexMedia: Total Matched using Property: " + total_match_property);
        ortus.api.DebugLog(INFO, "indexMedia: Total Movies Matched: " + total_movies_match);
        ortus.api.DebugLog(INFO, "indexMedia: Total Series Matched: " + total_series_match);
        ortus.api.DebugLog(INFO, "indexMedia: Total Missed: " + total_miss);
        ortus.api.DebugLog(INFO, "indexMedia: Total Bypassed: " + total_bypass);
        ortus.api.DebugLog(INFO, "indexMedia: Total Processed: " + total_processed);

        ortus.api.DebugLog(INFO, "indexMedia: Completed");

        return;
    }

public static boolean GetMediaMetaData(MediaObject mo) {

	boolean metadata_found = false;

        ortus.api.DebugLog(INFO, "GetMediaMetaData: Starting");

        List<String> regex = ortus.api.DumpLogFile(ortus.api.GetProperty("ortus/basepath","") + java.io.File.separator + "Configuration" + java.io.File.separator + "indexmedia.regex" );
        List<String> mediaregex = ortus.api.DumpLogFile(ortus.api.GetProperty("ortus/basepath", "") + java.io.File.separator + "Configuration" + java.io.File.separator + "mediamatch.regex" );

        if ( MediaFileAPI.GetMediaTitle(mo.GetMedia()).isEmpty()) {
		return false;
        }

        File mf = MediaFileAPI.GetFileForSegment(mo.GetMedia(),0);

	if ( mf == null ) {
		return false;
	}

	if ( ! mf.exists() ) {
	    return false;
	}

	if ( mf.getAbsoluteFile().toString().contains("Hauppauge")) {
	    return false;
	}

	List<Object> result = ortus.api.executeSQLQuery("select mediaid from sage.media where mediaid = " + MediaFileAPI.GetMediaFileID(mo.GetMedia()));
	if ( result.size() > 0 )
	    mo.SetMediaExist();
	else
	    ortus.api.DebugLog(TRACE, " media not found for " + MediaFileAPI.GetMediaFileID(mo.GetMedia()));

        if ( mo.IsMediaTypeRecording()) {
	    mo.SetLikelyTV();
            mo.SetShowTitle(ShowAPI.GetShowTitle(mo.GetMedia()));
            mo.SetEpisodeTitle(ShowAPI.GetShowEpisode(mo.GetMedia()));
	} else {
                String ShowPath = "";

                if( mf.getName().equals("VIDEO_TS") || mf.getName().equals("BDMV")) {
                    String workname = mf.getParent();
                    mo.SetShowTitle(workname.substring(workname.lastIndexOf(java.io.File.separator)+1));
                    mo.SetEpisodeTitle(mo.GetShowTitle());
                }else {
                    if ( mf.getName().contains("."))
                        mo.SetShowTitle(mf.getName().substring(0, mf.getName().lastIndexOf(".")));
                    else
                        mo.SetShowTitle(mf.getName());
                    String mediapath = mf.getParent();
                    mo.SetEpisodeTitle(mo.GetShowTitle());
                }
	}

	for ( String rx : regex ) {
	    Pattern pattern = Pattern.compile(rx);
	    Matcher matcher = pattern.matcher(mo.GetEpisodeTitle());
	    if ( matcher.matches()) {
		if ( matcher.groupCount() == 3) {
		    mo.SetLikelyTV();
		    ortus.api.DebugLog(TRACE2, "Show: " + matcher.group(1));
		    ortus.api.DebugLog(TRACE2, "Season No: " + matcher.group(2));
		    ortus.api.DebugLog(TRACE2, "Episode No: " + matcher.group(3));
		    mo.SetShowTitle(matcher.group(1));
		    mo.SetEpisodeTitle("S" + matcher.group(2) + "E" + matcher.group(3));
		} else
		    ortus.api.DebugLog(TRACE2, "Match found group: " + matcher.groupCount());
	    }
	}

	if (mo.ReadProperty())
		total_match_property++;
	
	if ( mo.IsLikelyTV() || mo.GetTVDBId() != null ) {
		mo.SetShowTitle(CleanName(mo.GetShowTitle()));
		if (TVSearch( mo,mediaregex)) {
			metadata_found = true;
		    ortus.api.DebugLog(TRACE2, "TV Matched");
		}
	}
	if ( ! metadata_found) {
		mo.SetMetadataSource("Google");
		if ( MovieSearch(mo, mediaregex)) {
		    metadata_found = true;
		    ortus.api.DebugLog(TRACE2, "Movie Matched");
		}
	}
	if ( ! metadata_found  && ! mo.IsLikelyTV()) {
		mo.SetShowTitle(CleanName(mo.GetShowTitle()));
		if (TVSearch( mo,mediaregex)) {
		    ortus.api.DebugLog(TRACE2, "TV Matched");
		}
	}

	if ( metadata_found) {
		ortus.cache.cacheEngine.getInstance().ReLoadCache(mo.GetMedia());
	}
	
        ortus.api.DebugLog(INFO, "GetMediaMetaData: Completed");

        return metadata_found;
    }

public static void AutoFileMatch(String filename) {
	ortus.api.DebugLog(INFO, "AutoFileMatch: Processing: " + filename);
	boolean media_found = false;
	List<Object> mo = new ArrayList();

	Object mf = MediaFileAPI.GetMediaFileForFilePath(new File(filename));
	if ( mf != null) {
		mo.add(mo);
		indexMedia(mo,1,1);
	}
	
	ortus.api.DebugLog("INFO", "AutoFileMatch: Completed");
	
	return;
}

//public static boolean PropertyMatch(MediaObject mo) {
//    ortus.api.DebugLog(TRACE2, "PropertyMatch: " +  MediaFileAPI.GetMediaFileID(mo.GetMedia()));
//
//    TheMovieDB tmdb = new TheMovieDB();
//
//    Movie tempmovie = new Movie();
//    if ( tempmovie.ReadProperty(mo.GetMedia())) {
//	Movie movie = null;
//        if ( ! tempmovie.GetId().equals("0") )
//            movie = tmdb.GetDetail("themoviedb:" + tempmovie.GetId());
//        else
//            movie = tmdb.GetDetail("imdb:" + tempmovie.GetIMDBId());
//        movie.SetMediaType(2);
//        movie.SetMetadataFound(true);
//        movie.WriteDB(mo.GetMedia());
//        if ( mo.IsFanartDownload() ) {
//            movie.DownloadImages(mo.GetMedia(),  "Movies" + java.io.File.separator + ortus.util.scrubString.ScrubFileName(movie.GetName()));
//        }
//        return true;
//    } else
//        return false;
//}


public static boolean TVSearch(MediaObject mo, List<String> mediaregex) {
    boolean xmlexist = false;
    ortus.api.DebugLog(TRACE2, "TVSearch: title " + mo.GetShowTitle() + " episode: " + mo.GetEpisodeTitle());
    String ortustvdbpath = ortus.api.GetSageProperty("ortus/basepath","") + java.io.File.separator + "tvdb" + java.io.File.separator;
    boolean series_found = false;
    database.WriteMediatoDB(mo);
    TheTVDB tvdb = new TheTVDB();

    if ( mo.GetTVDBId() == null) {
	    HashMap<String, Series> tv = new HashMap<String,Series>();

	    File tsf = new File(ortustvdbpath + mo.GetShowTitle() + java.io.File.separator + "en.xml");
	    if ( tsf.exists()) {
		ortus.api.DebugLog(TRACE2, "xml file is found, loading: " + tsf.getAbsolutePath());
		tv.put(mo.GetShowTitle(), tvdb.getSeries(ortustvdbpath + mo.GetShowTitle()));
		xmlexist = true;
	    }else {
//		ortus.api.DebugLog(TRACE2, "searching TVDB for series");
		tv = tvdb.searchSeries(mo.GetShowTitle(), "en");
	    }

	    Object[] tk = tv.keySet().toArray();
	    for ( Object tt : tk ) {
		if ( CompareTitle((String)tt, mo.GetShowTitle(), mediaregex)) {
			mo.SetTVDBId(tv.get((String)tt).getId());
			mo.SetName((String)tt);
		}
	    }

	    HashMap<String,String> logmatch = new HashMap<String,String>();
	    for ( Object tt : tk ) {
		logmatch.put((String)tt,(String)tt);
	    }
	    if ( logmatch.isEmpty())
		logmatch.put("Not Found", "Not Found");
	    database.LogFind(0, MediaFileAPI.GetMediaFileID(mo.GetMedia()), mo.GetShowTitle(), logmatch );
    }

    if ( mo.GetTVDBId() != null) {
	    mo.SetMediaTypeSeries();
            mo.SetName(mo.GetName().replaceAll(":",""));
            series_found = true;

            if ( ! xmlexist )
                tvdb.GetSeriesXML(mo.GetTVDBId(), ortustvdbpath + mo.GetName());
           
            List<Episode> episodes = tvdb.getEpisodes(ortustvdbpath + mo.GetName());
            Series current = tvdb.getSeries(ortustvdbpath + mo.GetName());
            List<Actor> actors = tvdb.getActors(ortustvdbpath + mo.GetName());
            String si = current.getId();
            if ( ! si.isEmpty()) {
                List<Object> result = ortus.api.executeSQLQuery("select seriesid from sage.series where seriesid = " + si);
                if ( result.size() <= 0) {
                    ortus.api.DebugLog(TRACE2,"Load Series into the db");
                    database.WriteSeriestoDB(current, actors);

                    for( Episode ce : episodes) {
                        database.WriteEpisodetoDB(ce ,current.getSeriesName());
                    }
                }
            }
            if ( mo.IsMetadataFull() || ! mo.IsMetadataExist()) {
                ortus.api.DebugLog(TRACE2, "metadata will be added to the db");
                mo.SetShowTitle(current.getSeriesName());
                database.UpdateEpisodeMediaID(mo);
            }

            if ( mo.IsFanartDownload() ) {
                boolean fo = false;
                if ( mo.IsFanartUpdate())
                    fo = false;
                if ( mo.IsFanartFull())
                    fo = true;
                tvdb.GetSeriesFanart(mo, ortustvdbpath, ortus.util.scrubString.ScrubFileName(current.getSeriesName()), fo);
            }
    }


    return series_found;
}

public static int ManualMovieSearch(Object mediafile, String title) {
    manual_index_running = true;
    ortus.api.DebugLog(TRACE2, "Manual Movie Search: title: " + title);

    int total_matches = 0;
    HashMap<String, String> movies;

    TheMovieDB tmdb = new TheMovieDB();
    movies = tmdb.Search(title);
    total_matches+=movies.size();
    database.LogFind(1, MediaFileAPI.GetMediaFileID(mediafile), title,  movies);
    Object[] mk = movies.keySet().toArray();
    for ( Object mt : mk ) {
        tmdb.GetDetail((String)movies.get(mt));
    }
    
    manual_index_running = false;

    return total_matches;
}

public static String GetScrapperCacheDescription(Object scrapperid) {
    String scrapper = GetProviderKey(scrapperid);

    if ( scrapper == null)
        return null;

    return new TheMovieDB().GetDetail(scrapper).GetOverview();
}

public static Object GetScrapperCacheDate(Object scrapperid) {
    String scrapper = GetProviderKey(scrapperid);

    if ( scrapper == null)
        return null;

    Date epoch;
        try {
            epoch = new java.text.SimpleDateFormat("yyyy-MM-dd").parse(new TheMovieDB().GetDetail(scrapper).GetReleaseDate());
        } catch (ParseException ex) {
            return null;
        }
    return epoch.getTime();
}

public static Object GetScrapperCacheMpaa(Object scrapperid) {

    String scrapper = GetProviderKey(scrapperid);
    
    if ( scrapper == null)
        return null;

    return new TheMovieDB().GetDetail(scrapper).GetRated();
}

private static String GetProviderKey(Object scrapperid) {
    String scrapperkey = "";
    List<List> result = ortus.api.executeSQLQueryArray("select foundkey from sage.scrapperlog where scrapperid = " + scrapperid);
    if ( result.size() == 1) {
       scrapperkey = (String)result.get(0).get(0);
       if ( scrapperkey.contains("Not Found") || scrapperkey.contains("None Found"))
           return null;
       else
           return scrapperkey;
    } else
       return null;
}
public static boolean ManualMovieMatch(Object mediafile, Object scrapperid, boolean download_fanart) {
    ortus.api.DebugLog(TRACE2, "ManualMovieMatch: " + scrapperid + " mediaid: " + MediaFileAPI.GetMediaFileID(mediafile));
    String scrapperkey = "";
    List<List> result = ortus.api.executeSQLQueryArray("select foundkey from sage.scrapperlog where scrapperid = " + scrapperid);
    if ( result.size() == 1) {
       scrapperkey = (String)result.get(0).get(0);
    } else
       return false;

    Movie movie = new TheMovieDB().GetDetail(scrapperkey);
    movie.SetMediaType(2);
    movie.SetMetadataFound(true);
    movie.WriteDB(mediafile);
    if ( download_fanart ) {
        movie.DownloadImages(mediafile, "Movies" + java.io.File.separator + ortus.util.scrubString.ScrubFileName(movie.GetName()));
    }

    return true;
}
public static boolean MovieSearch(MediaObject mo, List<String> mediaregex) {

    ortus.api.DebugLog(TRACE2, "MovieSearch: ShowTitle: " + mo.GetShowTitle());
    TheMovieDB tmdb = new TheMovieDB();
    boolean movie_found = false;

    if ( mo.GetTMDBId() == null && mo.GetIMDBId() == null) {
	    tmdb.SetSearchLimit(5);

	    HashMap<String, String> movies = tmdb.Search(mo.GetShowTitle());

	    database.LogFind(mo.GetScanType(), MediaFileAPI.GetMediaFileID(mo.GetMedia()), mo.GetShowTitle(),  movies);

	    Object[] mk = movies.keySet().toArray();
	    for ( Object mt : mk ) {
		if ( CompareTitle(ortus.onlinescrapper.tools.parser.CleanName((String)mt), ortus.onlinescrapper.tools.parser.CleanName(mo.GetShowTitle()), mediaregex)) {
			String[] keytype = movies.get(mt).split(":");
			if ( keytype[0].equals("imdb"))
				mo.SetIMDBId(keytype[1]);
			if ( keytype[0].equals("themoviedb"))
				mo.SetTMDBId(keytype[1]);
		}
	    }
    }

    if ( mo.GetTMDBId() != null || mo.GetIMDBId() != null ) {
	    movie_found = true;
	    mo.SetMediaTypeMovie();
	    Movie movie;
	    if ( mo.GetTMDBId() != null)
		movie = tmdb.GetDetail("themoviedb:" + mo.GetTMDBId());
	    else
		movie = tmdb.GetDetail("imdb:" + mo.GetIMDBId());
            movie.SetMetadataSource(mo.GetMetadataSource());
            movie.SetMediaGroup(mo.GetMediaGroup());
            movie.SetMediaType(2);
            movie.SetMetadataFound(true);
            if ( mo.IsMetadataFull() || ! mo.IsMetadataExist())
                movie.WriteDB(mo.GetMedia());
            if ( mo.IsFanartDownload())
                movie.DownloadImages(mo.GetMedia(), "Movies" + java.io.File.separator + ortus.util.scrubString.ScrubFileName(movie.GetName()));
    } else {
        Movie movie = new Movie();
        movie.SetMediaGroup(mo.GetMediaGroup());
        movie.WriteDB(mo.GetMedia());
    }

    return movie_found;
}

public static void GetMissingFanart() {
    index_running = true;
    st = ScanType.MissingFanart;
    cancel_scan = false;
    scan_start_time = new Date().getTime();
    scan_end_time = 0;
    total_movies_match = 0;
    total_bypass = 0;
    total_processed = 0;
    total_match_property = 0;
    total_miss = 0;
    total_series_match = 0;
    
    ortus.api.DebugLog(TRACE,"Fanart: Downloadming missing fanart");
    List<List> result = ortus.api.executeSQLQueryArray("select f.mediaid, f.type, f.url, m.mediatitle, m.mediatype from sage.fanart as f, sage.media as m where f.mediaid = m.mediaid and file is null order by 1");

    total_queue = result.size();
    ortus.api.DebugLog(TRACE2,"Fanart: found " + result.size() + " missing fanart records");
    int fanart_limit = Integer.parseInt(ortus.api.GetSageProperty("ortus/fanart/download_limit", "4"));
    int media_fanart_count = 0;
    int last_mediaid = 0;
    for( List fanart : result) {
	total_processed++;
	if ( last_mediaid == 0)
		last_mediaid = Integer.parseInt((String)fanart.get(0));

	if ( last_mediaid == Integer.parseInt((String)fanart.get(0)))
		media_fanart_count++;
	else
		media_fanart_count = 1;
	if ( media_fanart_count <= fanart_limit ) {
		total_movies_match++;
		String medtype = "Movies";
		if ( fanart.get(4).equals("1") || fanart.get(4).equals("3"))
			medtype = "TV";
		if ( cancel_scan ) {
		    index_running = false;
		    break;
		}
		ImageItem ii = new ImageItem((String)fanart.get(1),"0",(String)fanart.get(2));
		Object mediafile = MediaFileAPI.GetMediaFileForID(Integer.parseInt((String)fanart.get(0)));
		ii.getImage(mediafile, medtype + java.io.File.separator + ortus.util.scrubString.ScrubFileName((String)fanart.get(3)));
	} else
		total_bypass++;
	last_mediaid = Integer.parseInt((String)fanart.get(0));
    }

    scan_end_time = new Date().getTime();
    st = ScanType.None;
    index_running = false;
}

public static void GetScanFanart() {
    st = ScanType.FanartScan;
    ortus.api.DebugLog(INFO, "GetScanFanart: Starting");
    int total_backgrounds = 0;
    int total_posters = 0;
    int total_banners = 0;
    int total_season_poster = 0;
    int total_season_banner = 0;
    List<Object> mfl = new ArrayList<Object>(Arrays.asList(MediaFileAPI.GetMediaFiles("VDB")));

    for ( Object o : mfl ) {
	String Title = ortus.util.scrubString.ScrubFileName(ortus.api.GetMediaTitle(o));
	ortus.api.DebugLog(TRACE2,"Scanning for fanart for: " + Title);
	File fanartBackgrounds = new File(ortus.api.GetFanartFolder() +  java.io.File.separator + "Movies" + java.io.File.separator + Title + java.io.File.separator + "Backgrounds");
        if ( fanartBackgrounds.isDirectory())
		for (File fafile : fanartBackgrounds.listFiles()) {
			String fafilename = fafile.getAbsolutePath();
			if ( fafilename.endsWith("jpg") || fafilename.endsWith("png")) {
				total_backgrounds++;
				String faworkname = fafilename.substring(ortus.api.GetFanartFolder().length()+1);
				ortus.api.DebugLog(TRACE2,"GetScanFanart: Adding Background: " + faworkname);
				ImageItem ii = new ImageItem("Backgrounds","0",faworkname);
				ii.WriteFileImageDB(o);
			}

		}
	fanartBackgrounds = new File(ortus.api.GetFanartFolder() +  java.io.File.separator + "TV" + java.io.File.separator + Title + java.io.File.separator + "Backgrounds");
        if ( fanartBackgrounds.isDirectory())
		for (File fafile : fanartBackgrounds.listFiles()) {
			String fafilename = fafile.getAbsolutePath();
			if ( fafilename.endsWith("jpg") || fafilename.endsWith("png")) {
				total_backgrounds++;
				String faworkname = fafilename.substring(ortus.api.GetFanartFolder().length()+1);
				ortus.api.DebugLog(TRACE2,"GetScanFanart: Adding Background: " + faworkname);
				ImageItem ii = new ImageItem("Backgrounds","0",faworkname);
				ii.WriteFileImageDB(o);
			}

		}

	File fanartPosters = new File(ortus.api.GetFanartFolder() +  java.io.File.separator + "Movies" + java.io.File.separator + Title + java.io.File.separator + "Posters");
        if ( fanartPosters.isDirectory())
		for (File fafile : fanartPosters.listFiles()) {
			String fafilename = fafile.getAbsolutePath();
			if ( fafilename.endsWith("jpg") || fafilename.endsWith("png")) {
				total_posters++;
				String faworkname = fafilename.substring(ortus.api.GetFanartFolder().length()+1);
				ortus.api.DebugLog(TRACE2,"GetScanFanart: Adding Poster: " + faworkname);
				ImageItem ii = new ImageItem("Posters","0",faworkname);
				ii.WriteFileImageDB(o);
			}
		}
	fanartPosters = new File(ortus.api.GetFanartFolder() +  java.io.File.separator + "TV" + java.io.File.separator + Title + java.io.File.separator + "Posters");
        if ( fanartPosters.isDirectory())
		for (File fafile : fanartPosters.listFiles()) {
			String fafilename = fafile.getAbsolutePath();
			if ( fafilename.endsWith("jpg") || fafilename.endsWith("png")) {
				total_posters++;
				String faworkname = fafilename.substring(ortus.api.GetFanartFolder().length()+1);
				ortus.api.DebugLog(TRACE2,"GetScanFanart: Adding Poster: " + faworkname);
				ImageItem ii = new ImageItem("Posters","0",faworkname);
				ii.WriteFileImageDB(o);
			}
		}
		File fanartBanners = new File(ortus.api.GetFanartFolder() + java.io.File.separator + "TV" + java.io.File.separator + Title + java.io.File.separator + "Banners");
		if (fanartBanners.isDirectory()) {
			for (File fafile : fanartBanners.listFiles()) {
				String fafilename = fafile.getAbsolutePath();
				if (fafilename.endsWith("jpg") || fafilename.endsWith("png")) {
					total_banners++;
					String faworkname = fafilename.substring(ortus.api.GetFanartFolder().length() + 1);
					ortus.api.DebugLog(TRACE2, "GetScanFanart: Adding Banner: " + faworkname);
					ImageItem ii = new ImageItem("Banners", "0", faworkname);
					ii.WriteFileImageDB(o);
				}
			}
		}

		File fanartSeason = new File(ortus.api.GetFanartFolder() + java.io.File.separator + "TV" + java.io.File.separator + Title);
		if (fanartSeason.isDirectory()) {
			for (File sfile : fanartSeason.listFiles()) {
				if (sfile.isDirectory() && sfile.getName().startsWith("Season")) {
					Pattern pattern = Pattern.compile("Season.*(\\d)");
					Matcher matcher = pattern.matcher(sfile.getName());
					String seasonno = "0";
					if ( matcher.find())
						seasonno = matcher.group(1);
					fanartPosters = new File(sfile.getAbsolutePath() + java.io.File.separator + "Posters");
					if (fanartPosters.isDirectory()) {
						for (File fafile : fanartPosters.listFiles()) {
							String fafilename = fafile.getAbsolutePath();
							if (fafilename.endsWith("jpg") || fafilename.endsWith("png")) {
								total_season_poster++;
								String faworkname = fafilename.substring(ortus.api.GetFanartFolder().length() + 1);
								ortus.api.DebugLog(TRACE2, "GetScanFanart: Adding Poster: " + faworkname);
								ImageItem ii = new ImageItem("Season-" + seasonno + "-Posters", "0", faworkname);
								ii.WriteFileImageDB(o);
							}
						}
					}
					fanartBanners = new File(sfile.getAbsolutePath() + java.io.File.separator + "Banners");
					if (fanartBanners.isDirectory()) {
						for (File fafile : fanartBanners.listFiles()) {
							String fafilename = fafile.getAbsolutePath();
							if (fafilename.endsWith("jpg") || fafilename.endsWith("png")) {
								total_season_banner++;
								String faworkname = fafilename.substring(ortus.api.GetFanartFolder().length() + 1);
								ortus.api.DebugLog(TRACE2, "GetScanFanart: Adding Banner: " + faworkname);
								ImageItem ii = new ImageItem("Season-" + seasonno + "-Banners", "0", faworkname);
								ii.WriteFileImageDB(o);
							}
						}
					}
				}
			}
		}


	}
    ortus.api.DebugLog(TRACE2,"GetScanFanart: Processed " + total_backgrounds + " Backgrounds");
    ortus.api.DebugLog(TRACE2,"GetScanFanart: Processed " + total_posters + " Posters");
    ortus.api.DebugLog(TRACE2,"GetScanFanart: Processed " + total_banners + " Banners");
    ortus.api.DebugLog(TRACE2,"GetScanFanart: Processed " + total_season_poster + " Season Posters");
    ortus.api.DebugLog(TRACE2,"GetScanFanart: Processed " + total_season_banner + " Season Banners");
    ortus.api.DebugLog(TRACE2,"GetScanFanart: Completed");
    st = ScanType.None;
}
//public static IMDBItem IMDBMovieDetail(String imdbid) {
//    ortus.api.DebugLog(TRACE2,"IMDBProvider: IMDBMovieDetail: " + imdbid);
//    IMetaDataProvider dp = new ortus.onlinescrapper.IMDBProvider();

//    IMDBItem movie = dp.GetItemDetail(imdbid);

///    movie.WriteDB(mo);

//    return dummy;
//}

private static boolean CompareTitle(String TMDBtitle, String title, List<String> mediaregex) {
    boolean titlematch = false;

    String cleanTMDBtitle = ortus.api.ExtremeScrubStringTitle(TMDBtitle);
    String cleantitle = ortus.api.ExtremeScrubStringTitle(title);

    ortus.api.DebugLog(TRACE2, "title: <" + title + ">   cleantitle: <" + cleantitle + ">   Provider title: <" + TMDBtitle + ">   clean Provider title: <" + cleanTMDBtitle + ">");
    if ( cleanTMDBtitle.equals(cleantitle))
        return true;
    else {
        int matchfound = 0;
        Pattern pattern;
        Matcher matcher;
        for ( String mr : mediaregex) {
           String[] reg = mr.split(":");
           pattern = Pattern.compile(reg[0]);
           matcher = pattern.matcher(cleantitle);
           StringBuffer sb3 = new StringBuffer(cleantitle.length());
           while (matcher.find()) {
              matchfound++;
              matcher.appendReplacement(sb3, Matcher.quoteReplacement(reg[1]));
           }

           matcher.appendTail(sb3);
           String newcleantitle = sb3.toString();
           if ( matchfound > 0) {
               ortus.api.DebugLog(TRACE2, "title: <" + title + ">   cleantitle: <" + cleantitle + ">   Provider title: <" + TMDBtitle + ">   clean Provider title: <" + cleanTMDBtitle + ">");

               if( cleanTMDBtitle.equals(newcleantitle))
                  return true;
           }
           matchfound=0;
         }

        pattern = Pattern.compile("(\\d+)");
        matcher = pattern.matcher(TMDBtitle);
        StringBuffer sb = new StringBuffer(TMDBtitle.length());

        while (matcher.find())
            matcher.appendReplacement(sb, Matcher.quoteReplacement(binaryToRoman(Integer.parseInt(matcher.group(0).trim()))));

        matcher.appendTail(sb);
        cleanTMDBtitle = ortus.api.ExtremeScrubStringTitle(sb.toString());

        StringBuffer sb2 = new StringBuffer(title.length());
        matcher = pattern.matcher(title);
        while (matcher.find())
           matcher.appendReplacement(sb2, Matcher.quoteReplacement(binaryToRoman(Integer.parseInt(matcher.group(0).trim()))));
        matcher.appendTail(sb2);
        cleantitle = ortus.api.ExtremeScrubStringTitle(sb2.toString());
        ortus.api.DebugLog(TRACE2, "title: <" + title + ">   cleantitle: <" + cleantitle + ">   Provider title: <" + TMDBtitle + ">   clean Provider title: <" + cleanTMDBtitle + ">");

        if ( cleanTMDBtitle.equals(cleantitle))
            return true;
    }
    return false;
}

public static String binaryToRoman(int binary) {

    String[] RCODE = {"m", "cm", "d", "cd", "c", "xc", "l","xl", "x", "ix", "v", "iv", "i"};
    int[]   BVAL  = {1000, 900, 500, 400,  100,   90,  50, 40,   10,    9,   5,   4,    1};

    if (binary <= 0 || binary >= 4000) {
        return "";
    }
    String roman = "";        

    for (int i = 0; i < RCODE.length; i++) {
        while (binary >= BVAL[i]) {
            binary -= BVAL[i];
            roman  += RCODE[i];
        }
    }
    return roman;
}

public static String CleanName(String title) {
    String s1 = title.toLowerCase();
    s1 = s1.replaceAll("\\."," " );
    s1 = s1.replaceAll("_"," ");
    s1 = s1.replaceAll("-"," ");

    return s1;
}
}
class DirectoryFilter implements FileFilter
{
    @Override
   public boolean accept(File file)
   {
      return file.isDirectory();
   }
}
